package com.nstc.sftpExchange.util;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class BeanToMap {
    /**
     * 将实体对象转换为Map
     * @param obj 实体对象
     * @return Map<String, Object>
     */
    public static Map<String, Object> beanToMap(Object obj) {
        return beanToMap(obj, false);
    }

    /**
     * 将实体对象转换为Map
     * @param obj 实体对象
     * @param includeNullValue 是否包含空值
     * @return Map<String, Object>
     */
    public static Map<String, Object> beanToMap(Object obj, boolean includeNullValue) {
        if (obj == null) {
            return null;
        }

        Map<String, Object> map = new HashMap<>();
        Class<?> clazz = obj.getClass();

        // 获取所有字段（包括父类字段）
        Field[] fields = getAllFields(clazz);

        for (Field field : fields) {
            try {
                field.setAccessible(true);
                String fieldName = field.getName();
                Object fieldValue = field.get(obj);

                // 根据参数决定是否包含空值
                if (includeNullValue || fieldValue != null) {
                    map.put(fieldName, fieldValue);
                }
            } catch (IllegalAccessException e) {

            }
        }

        return map;
    }

    /**
     * 通过getter方法将实体对象转换为Map
     * @param obj 实体对象
     * @return Map<String, Object>
     */
    public static Map<String, Object> beanToMapByGetter(Object obj) {
        return beanToMapByGetter(obj, false);
    }

    /**
     * 通过getter方法将实体对象转换为Map
     * @param obj 实体对象
     * @param includeNullValue 是否包含空值
     * @return Map<String, Object>
     */
    public static Map<String, Object> beanToMapByGetter(Object obj, boolean includeNullValue) {
        if (obj == null) {
            return null;
        }

        Map<String, Object> map = new HashMap<>();
        Class<?> clazz = obj.getClass();

        // 获取所有方法
        Method[] methods = clazz.getMethods();

        for (Method method : methods) {
            String methodName = method.getName();

            // 判断是否为getter方法
            if (isGetterMethod(methodName)) {
                try {
                    // 获取字段名
                    String fieldName = getFieldNameFromGetter(methodName);
                    Object fieldValue = method.invoke(obj);

                    // 根据参数决定是否包含空值
                    if (includeNullValue || fieldValue != null) {
                        map.put(fieldName, fieldValue);
                    }
                } catch (Exception e) {

                }
            }
        }

        return map;
    }

    /**
     * 获取类的所有字段（包括父类字段）
     * @param clazz 类
     * @return Field数组
     */
    private static Field[] getAllFields(Class<?> clazz) {
        // 使用列表存储所有字段
        java.util.List<Field> fieldList = new java.util.ArrayList<>();

        // 遍历类层次结构
        while (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                // 排除静态字段
                if (!java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
                    fieldList.add(field);
                }
            }
            clazz = clazz.getSuperclass();
        }

        return fieldList.toArray(new Field[0]);
    }

    /**
     * 判断是否为getter方法
     * @param methodName 方法名
     * @return boolean
     */
    private static boolean isGetterMethod(String methodName) {
        return (methodName.startsWith("get") && methodName.length() > 3) ||
                (methodName.startsWith("is") && methodName.length() > 2);
    }

    /**
     * 从getter方法名获取字段名
     * @param methodName getter方法名
     * @return 字段名
     */
    private static String getFieldNameFromGetter(String methodName) {
        if (methodName.startsWith("get")) {
            String fieldName = methodName.substring(3);
            return fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
        } else if (methodName.startsWith("is")) {
            String fieldName = methodName.substring(2);
            return fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
        }
        return methodName;
    }

    /**
     * Map转实体对象
     * @param map Map对象
     * @param clazz 实体类Class
     * @param <T> 实体类类型
     * @return 实体对象
     */
    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
        if (map == null || clazz == null) {
            return null;
        }

        try {
            T obj = clazz.newInstance();
            Field[] fields = getAllFields(clazz);

            for (Field field : fields) {
                String fieldName = field.getName();
                if (map.containsKey(fieldName)) {
                    field.setAccessible(true);
                    Object value = map.get(fieldName);

                    // 类型转换
                    if (value != null && !field.getType().isAssignableFrom(value.getClass())) {
                        value = convertValue(value, field.getType());
                    }

                    field.set(obj, value);
                }
            }

            return obj;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 简单类型转换
     * @param value 值
     * @param targetType 目标类型
     * @return 转换后的值
     */
    private static Object convertValue(Object value, Class<?> targetType) {
        if (value == null) {
            return null;
        }

        String stringValue = value.toString();

        if (targetType == String.class) {
            return stringValue;
        } else if (targetType == Integer.class || targetType == int.class) {
            return Integer.valueOf(stringValue);
        } else if (targetType == Long.class || targetType == long.class) {
            return Long.valueOf(stringValue);
        } else if (targetType == Double.class || targetType == double.class) {
            return Double.valueOf(stringValue);
        } else if (targetType == Float.class || targetType == float.class) {
            return Float.valueOf(stringValue);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            return Boolean.valueOf(stringValue);
        } else if (targetType == Byte.class || targetType == byte.class) {
            return Byte.valueOf(stringValue);
        } else if (targetType == Short.class || targetType == short.class) {
            return Short.valueOf(stringValue);
        }

        return value;
    }
}
